﻿#include "TreeWidget_EditScriptList.h"

#include "qmessagebox.h"
#include "qlist.h"

#include "ScriptInstruction.h"
#include "InstructionLoop.h"

TreeWidget_EditScriptList::TreeWidget_EditScriptList(QWidget* parent):QTreeWidget(parent)
{
  connect(this, &QTreeWidget::itemClicked, this, &TreeWidget_EditScriptList::slot_itemClicked);
}

TreeWidget_EditScriptList::~TreeWidget_EditScriptList()
{
  for (int i=0;i<topLevelItemCount();++i)
    {
      circularDelete(takeTopLevelItem(i));
    }
}

void TreeWidget_EditScriptList::circularDelete(QTreeWidgetItem* parent)
{
  for (int i=0;i<parent->childCount();++i)
    {
      circularDelete(parent->child(i));
    }
  delete parent;
}

void TreeWidget_EditScriptList::itemOperation(ListOperation operationFlag)
{
  QTreeWidgetItem* currentNode = currentItem();//得到当前节点
  if (currentNode == Q_NULLPTR)
    {//当前节点为空代表没有选中节点，直接弹出提醒
      QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("先选中一个操作"));
      return;
    }
  QTreeWidgetItem* currentParent = currentNode->parent();//当前节点不为空则取其父节点
  if (currentParent != Q_NULLPTR)
    {//若父节点不是空的，则直接在当前父节点下面操作节点
      int index = currentParent->indexOfChild(currentNode);//得到当前节点在父节点的位置
      QTreeWidgetItem* newNode = Q_NULLPTR;
      switch (operationFlag)
        {
        case Clone:
          newNode = currentNode->clone();
          currentParent->insertChild(index + 1, newNode);
          setCurrentItem(newNode);//将操作后的节点设置为当前节点
          break;
        case MoveUp:
          if (index > 0)
            {//若当前节点所在位置在合法范围内，上移一位
              currentParent->takeChild(index);
              currentParent->insertChild(index - 1, currentNode);
              setCurrentItem(currentNode);
            }
          else
            {//若当前节点超出合法范围，弹出提示框
              QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法再上移"));
            }
          break;
        case MoveDown:
          if (index < currentParent->childCount() - 1)
            {//若当前节点所在位置在合法范围内，下移一位
              currentParent->takeChild(index);
              currentParent->insertChild(index + 1, currentNode);
              setCurrentItem(currentNode);
            }
          else
            {//若当前节点超出合法范围，弹出提示框
              QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法再下移"));
            }
          break;
        case Remove:
          delete currentParent->takeChild(index);
          break;
        default:
          QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法识别的操作"));
          break;
        }
      return;
    }
  else
    {//当前节点的父节点为空代表当前节点是顶层节点
      int index = indexOfTopLevelItem(currentNode);//得到当前节点在顶层的位置
      QTreeWidgetItem* newNode = Q_NULLPTR;
      switch (operationFlag)
        {
        case Clone:
          newNode = currentNode->clone();
          insertTopLevelItem(index + 1, newNode);
          setCurrentItem(newNode);//将操作后的节点设置为当前节点
          break;
        case MoveUp:
          if (index > 0)
            {//若当前节点所在位置在合法范围内，上移一位
              takeTopLevelItem(index);
              insertTopLevelItem(index - 1, currentNode);
              setCurrentItem(currentNode);
            }
          else
            {//若当前节点超出合法范围，弹出提示框
              QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法再上移"));
            }
          break;
        case MoveDown:
          if (index < topLevelItemCount() - 1) {//若当前节点所在位置在合法范围内，下移一位
              takeTopLevelItem(index);
              insertTopLevelItem(index + 1, currentNode);
              setCurrentItem(currentNode);
            }
          else {//若当前节点超出合法范围，弹出提示框
              QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法再下移"));
            }
          break;
        case Remove:
          delete takeTopLevelItem(index);//删除节点
          break;
        default:
          QMessageBox::information(this, QStringLiteral("消息"), QStringLiteral("无法识别的操作"));
          break;
        }
      return;
    }
}
void TreeWidget_EditScriptList::slot_itemClicked(QTreeWidgetItem* item, int column)
{
  (void)column;
  if (previousItem != item) {
      previousItem = item;
    }
  else {
      setCurrentItem(Q_NULLPTR);
      previousItem = Q_NULLPTR;
    }
}

void TreeWidget_EditScriptList:: addOperationNameToList(ScriptInstruction* scriptInstruction)
{
  ScriptNode* newNode = new ScriptNode();//新建单个脚本节点
  newNode->setText(0, scriptInstruction->toString());//命名新建脚本节点
  newNode->scriptInstruction=scriptInstruction;//设置附属的指令
  QTreeWidgetItem* currentNode = currentItem();//得到当前节点
  if (currentNode == Q_NULLPTR)
    {
      //当前节点为空代表没有选中节点，直接在最后添加新的节点
      addTopLevelItem(newNode);
    }
  else
    {
      ScriptNode* currentNode = dynamic_cast<ScriptNode*>(currentNode);//转换格式
      if (currentNode->scriptInstruction->getInstructionFlag()==ScriptInstruction::MetaInstruction_Loop)//如果循环节点-位置映射表中有当前节点，则当前节点是循环节点
        {
          //如果该节点是一个循环，则为其添加子节点
          currentNode->addChild(newNode);
        }
      else//当前节点不是循环节点
        {
          QTreeWidgetItem* currentParent = currentNode->parent();//当前节点不为空，且不是循环，则取其父节点
          if (currentParent != Q_NULLPTR)
            {//若父节点不是空的，则直接在当前父节点下面添加新的节点
              int index = currentParent->indexOfChild(currentNode);//得到当前节点在父节点的位置
              currentParent->insertChild(index + 1, newNode);//将新的节点添加到当前位置+1的位置
            }
          else
            {//当前节点的父节点为空代表当前节点是顶层节点
              int index = indexOfTopLevelItem(currentNode);//得到当前节点在顶层的位置
              insertTopLevelItem(index + 1, newNode);//将新节点插入到当前位置+1的位置
            }
        }
    }
  setCurrentItem(newNode);//将新节点设置为当前节点
}

QList<ScriptInstruction*> TreeWidget_EditScriptList::getScriptList()
{
  QList<ScriptInstruction*> scriptList;
  QList<int> nodeIndexStack;//节点索引栈
  QList<int> nodeCountStack;//节点计数栈
  for (int i = 0; i < topLevelItemCount(); ++i)
    {
      QTreeWidgetItem * currentItem = topLevelItem(i);
      scriptList.append(dynamic_cast<ScriptNode*>(currentItem)->scriptInstruction);
      int count=currentItem->childCount();
      if(count==0)
        {
          continue;
        }
      dynamic_cast<InstructionLoop*>(scriptList.last())->setInstructionCount(count);
      nodeIndexStack.append(0);//初始位置入栈
      nodeCountStack.append(count);//当前节点的子节点数量入栈
      currentItem=currentItem->child(0);
      while (!nodeCountStack.isEmpty())//节点计数栈不为空才进行迭代
        {
          scriptList.append(dynamic_cast<ScriptNode*>(currentItem)->scriptInstruction);
          currentItem=currentItem->parent()->child(++nodeIndexStack.last());
          int count=currentItem->childCount();
          if(count>0)
            {
              dynamic_cast<InstructionLoop*>(scriptList.last())->setInstructionCount(count);
              nodeIndexStack.append(0);//初始位置入栈
              nodeCountStack.append(count);//当前节点的子节点数量入栈
              currentItem=currentItem->child(0);
              continue;
            }
          if(nodeIndexStack.last()==nodeCountStack.last())//节点索引栈栈顶值等于对应层的计数时
            {
              nodeIndexStack.removeLast();//出栈
              nodeCountStack.removeLast();//出栈
              currentItem=currentItem->parent();
            }
        }
    }
  return scriptList;
}

TreeWidget_EditScriptList* TreeWidget_EditScriptList::setScriptList(QList<ScriptInstruction*> scriptList)
{
  clear();
  QList<ScriptNode*> loopNodeStack;//循环节点栈
  QList<uint> instructionCountStack;//指令计数栈
  for(ScriptInstruction* scriptInstruction:scriptList)
    {
      ScriptNode* newNode=new ScriptNode();//创建新的节点
      newNode->setText(0,scriptInstruction->toString());//给节点命名
      newNode->scriptInstruction=scriptInstruction;//设置附属的脚本指令
      if(loopNodeStack.isEmpty())//若循环节点栈为空则说明当前处于顶层
        {
          addTopLevelItem(newNode);//将新节点添加到顶层的最后
        }
      else//若循环节点栈不为空则说明当前处于某个循环节点下
        {
          loopNodeStack.last()->addChild(newNode);//将新节点添加到栈顶所指的循环节点下
          if(!--instructionCountStack.last())
            {
              //如果指令计数栈栈顶值自减一后等于零，则说明该层循环结束
              loopNodeStack.removeLast();//循环节点栈出栈
              instructionCountStack.removeLast();//指令计数栈出栈
            }
        }
      if(ScriptInstruction::MetaInstruction_Loop==scriptInstruction->getInstructionFlag())
        {
          //如果当前脚本指令是循环指令
          //添加该循环指令的指令计数到指令计数栈
          instructionCountStack.append(dynamic_cast<InstructionLoop*>(scriptInstruction)->getInstructionCount());
          loopNodeStack.append(newNode);//添加该节点到循环节点栈，表明当前处于的层级在该循环下
        }
    }
  return this;
}

ScriptNode::ScriptNode()
{}

ScriptNode::ScriptNode(const ScriptNode& scriptNode)
{
  *this=scriptNode;
}

ScriptNode& ScriptNode::operator=(const ScriptNode& scriptNode)
{
  *(QTreeWidgetItem*)this=scriptNode;
  scriptInstruction=scriptNode.scriptInstruction->clone();
  return *this;
}

ScriptNode::~ScriptNode()
{
  delete scriptInstruction;
}

QTreeWidgetItem *ScriptNode::clone() const
{
  return new ScriptNode(*this);
}
